package com.yeziji.job.config.support.handler;

import com.yeziji.job.annotation.EnabledAutoRegisterYzjJob;
import com.yeziji.job.annotation.YzjJob;
import com.yeziji.job.annotation.YzjJobBean;
import com.yeziji.job.common.JobHolder;
import com.yeziji.utils.expansion.Lists2;
import com.yeziji.utils.expansion.Spring2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.lang.NonNull;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 自动注册任务处理器
 *
 * @author hwy
 * @since 2024/05/08 17:41
 **/
@Slf4j
public class AutoRegisterJobHandler implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    /**
     * 环境
     */
    private Environment environment;
    /**
     * 资源加载器
     */
    private ResourceLoader resourceLoader;

    @Override
    public void setEnvironment(@NonNull Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(@NonNull ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void registerBeanDefinitions(@NonNull AnnotationMetadata importingClassMetadata, @NonNull BeanDefinitionRegistry registry) {
        // 扫描指定的 loader
        ClassPathScanningCandidateComponentProvider scanner = Spring2.getScanner(this.environment, this.resourceLoader);

        // 设置扫描过滤条件
        scanner.addIncludeFilter(new AnnotationTypeFilter(YzjJobBean.class));

        // 获取扫描并遍历 basePackages
        List<Class<?>> classes = new ArrayList<>();
        Set<String> basePackages = Spring2.getBasePackages(EnabledAutoRegisterYzjJob.class, importingClassMetadata);
        for (String basePackage : basePackages) {
            // 通过 scanner 获取 basePackage 下的候选类(有标 @YzjJobBean 注解的类)
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
            // 遍历每一个候选类，如果符合条件就把他们注册到容器并记录他底下的 YzjJob 注解; 注册到缓存之中
            for (BeanDefinition candidateComponent : candidateComponents) {
                String beanClassName = candidateComponent.getBeanClassName();
                registry.registerBeanDefinition(String.format("yzjJobBean$%s", beanClassName), candidateComponent);
                // save bean class
                try {
                    classes.add(Class.forName(beanClassName));
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        // register holder
        if (Lists2.isNotEmpty(classes)) {
            for (Class<?> clazz : classes) {
                Method[] declaredMethods = clazz.getDeclaredMethods();
                for (Method declaredMethod : declaredMethods) {
                    if (declaredMethod.isAnnotationPresent(YzjJob.class)) {
                        YzjJob annotation = declaredMethod.getAnnotation(YzjJob.class);
                        String jobName = annotation.value();
                        if (JobHolder.contain(jobName)) {
                            log.warn(">>> {} duplicate register: {}", jobName, JobHolder.get(jobName));
                            continue;
                        }
                        JobHolder.put(jobName, clazz);
                    }
                }
            }
        }
    }
}
